/* -----------------------------------------------------------------------------

Medieval Madness 2
http://code.google.com/p/medievalmadness/

Medieval Madness is a mod to encourage melee combat. Unlike other melee mods, it does not
force anyone to participate, although it creates a number of incentives to do so.

The basic tagline is: "Modern Weapons are witchcraft, real men use melee."

Although the mod itself is slightly more complicated:


Authors:
- Brian 'ThriKreen' Chung <thrikreen@animecafe.net>
- Georg Zoeller

----------------------------------------------------------------------------- */


// -----------------------------------------------------------------------------
// Libraries
//
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <tf2>
#include <tf2_stocks>
#undef REQUIRE_PLUGIN

#define BLACK                       {200,200,200,192}
#define INVIS                       {255,255,255,0}
#define NORMAL                      {255,255,255,255}

#define POTION_MINOR_VITALITY       0
#define POTION_FLIGHT               1
#define POTION_MAJOR_VITALITY       2
#define POTION_SPEED                3
#define POTION_INVISIBILITY         4
#define POTION_FLAME                5
#define POTION_CRIT                 6
#define POTION_INVULN               7

#define MAX_POTIONS                 8

#define PLAYER_STATUS               0
#define PLAYER_TIMESTAMP            1
#define PLAYER_EFFECT               2
#define PLAYER_EXTRA                3
#define PLAYER_FLAG                 4
#define PLAYER_EXTRA2               5

#define PLAYER_FLAG_BURNME          1
#define PLAYER_FLAG_AUTOCRIT        1

#define DIRTY_HACK                  100


// -----------------------------------------------------------------------------
// Plugin Info
//
public Plugin:myinfo =
{
    name = "SR Medieval Madness 2",
    author = "thrikreen@animecafe.net",
    description = "Medieval mode for TF2 (melee only mode, with some exceptions, and rewards and punishments system)",
    version = SOURCEMOD_VERSION,
    url = "http://code.google.com/p/medievalmadness/"
};


// -----------------------------------------------------------------------------
// Global Variables
//
new g_Debug = true;                 // Debug information
new Handle:g_hHud                   = INVALID_HANDLE;

// Cvars Handles and global variables
new Handle:g_hCvarEnable            = INVALID_HANDLE;
new Handle:g_hCvarGoldCap           = INVALID_HANDLE;
new Handle:g_hCvarGoldCapWitch      = INVALID_HANDLE;
new Handle:g_hCvarGoldDomination    = INVALID_HANDLE;
new Handle:g_hCvarGoldRevenge       = INVALID_HANDLE;
new Handle:g_hCvarGoldAssistKill    = INVALID_HANDLE;
new Handle:g_hCvarGoldWitchBounty   = INVALID_HANDLE;
new Handle:g_hCvarShopWitchCost     = INVALID_HANDLE;
new g_CvarEnable                    = false;
new g_CvarGoldCap                   = 0;
new g_CvarGoldCapWitch              = 0;
new g_CvarGoldDomination            = 0;
new g_CvarGoldRevenge               = 0;
new g_CvarGoldAssistKill            = 0;
new g_CvarGoldWitchBounty           = 0;
new Float:g_CvarShopWitchCost       = 0.0;

// Property Offsets
new g_cloakOffset       = -1;
new g_wearableOffset    = -1;
new g_shieldOffset      = -1;
new g_condOffset;

// Player Information
new IsPlayerAWitch[MAXPLAYERS+1];
new PlayerGoldCount[MAXPLAYERS+1];
new PlayerBounty[MAXPLAYERS+1];
new PlayerPotions[MAXPLAYERS+1][MAX_POTIONS];
new PlayerAutoBuy[MAXPLAYERS+1];

new Handle:PlayerEffectTimers[MAXPLAYERS+1][2]; // 0 for end effects timer & 1 for repeating timer
new PlayerEffectTracker[MAXPLAYERS+1][6];

// Store
enum MFPotion_Type
{
    MFPotion_Vitality,
    MKPotion_Flight,
    MKPotion_GreatVitality,
    MKPotion_Speed,
    MKPotion_Invisibility,
    MKPotion_Fire,
    MKPotion_Critz,
    MKPotion_Invulnerability,
    MFPotion_End
};

new String:g_StoreInventory[MAX_POTIONS][30]={"Potion of Vitality","Potion of Flight", "Potion of Great Vitality", "Potion of Speed","Potion of Invisibility","Potion of Fire", "Potion of Critz", "Potion of Invulnerability" };
new g_StorePrices[MAX_POTIONS] ={2,3,4,5,6,7,10,13};



// -----------------------------------------------------------------------------
// Plugin Initialization
//
public OnPluginStart()
{
    // Init any Global Variables
    g_hHud = CreateHudSynchronizer();           // HUD sync
    g_condOffset = FindSendPropInfo("CTFPlayer", "m_nPlayerCond");


    for (new i=1; i<(MAXPLAYERS+1); i++)
    {
        IsPlayerAWitch[i] = 0;
        PlayerGoldCount[i] = 1;
        PlayerBounty[i] = 0;
        PlayerAutoBuy[i] = 0;
        for (new j=0; j<MAX_POTIONS; j++)
        {
            PlayerPotions[i][j] = 0;
        }
    }


    // -----------------------------------------------------------------------------
    // Cvars
    //
    g_hCvarEnable           = CreateConVar("sm_medieval",                   "1", "Enables/disables the Medieval Madness plugin.");
    g_hCvarGoldCap          = CreateConVar("sm_medieval_gold_cap",          "4", "Gold awarded for capturing the point or flag.");
    g_hCvarGoldCapWitch     = CreateConVar("sm_medieval_gold_capwitch",     "1", "Gold awarded for capturing the point or flag, by a witch.");
    g_hCvarGoldDomination   = CreateConVar("sm_medieval_gold_domination",   "2", "Gold awarded for getting a domination.");
    g_hCvarGoldRevenge      = CreateConVar("sm_medieval_gold_revenge",      "1", "Gold awarded for getting a revenge.");
    g_hCvarGoldAssistKill   = CreateConVar("sm_medieval_gold_assistkill",   "1", "Gold awarded for assisting in a kill.");
    g_hCvarGoldWitchBounty  = CreateConVar("sm_medieval_gold_witchbounty",  "1", "Bounty increase for each kill as a witch.");

    g_hCvarShopWitchCost    = CreateConVar("sm_medieval_shop_witchcost",    "2.0", "Multiplier of shop potions for witches");

    // Global Variables
    g_CvarEnable            = GetConVarInt(g_hCvarEnable);
    g_CvarGoldCap           = GetConVarInt(g_hCvarGoldCap);
    g_CvarGoldCapWitch      = GetConVarInt(g_hCvarGoldCapWitch);
    g_CvarGoldDomination    = GetConVarInt(g_hCvarGoldDomination);
    g_CvarGoldRevenge       = GetConVarInt(g_hCvarGoldRevenge);
    g_CvarGoldAssistKill    = GetConVarInt(g_hCvarGoldAssistKill);
    g_CvarGoldWitchBounty   = GetConVarInt(g_hCvarGoldWitchBounty);
    g_CvarShopWitchCost     = GetConVarFloat(g_hCvarShopWitchCost);

    // Hooks
    HookConVarChange(g_hCvarEnable,         OnCvarChanged);
    HookConVarChange(g_hCvarGoldCap,        OnCvarChanged);
    HookConVarChange(g_hCvarGoldCapWitch,   OnCvarChanged);
    HookConVarChange(g_hCvarGoldDomination, OnCvarChanged);
    HookConVarChange(g_hCvarGoldRevenge,    OnCvarChanged);
    HookConVarChange(g_hCvarGoldAssistKill, OnCvarChanged);
    HookConVarChange(g_hCvarGoldWitchBounty, OnCvarChanged);
    HookConVarChange(g_hCvarShopWitchCost,  OnCvarChanged);


    // -----------------------------------------------------------------------------
    // Event Hooks
    //
    HookEvent("player_spawn", Event_PlayerSpawn);
    HookEvent("player_hurt", Event_PlayerHurt);
    HookEvent("player_death", Event_PlayerDeath);

    HookEvent("teamplay_round_active", Event_RoundStart);
    HookEvent("teamplay_point_captured", Event_PointCaptured);

    HookEvent("player_builtobject", Event_PlayerBuiltObject);


    // -----------------------------------------------------------------------------
    // Register console commands
    //
    RegConsoleCmd("gold", Command_SayGold);
    RegConsoleCmd("inv", Command_SayInventory);
    RegConsoleCmd("shop", Command_SayShop);
    RegConsoleCmd("drink", Command_SayDrink);
    RegConsoleCmd("qdrink", Command_SayqDrink);
    RegConsoleCmd("repent", Command_SayRepent);
    RegConsoleCmd("autoshop", Command_SayAutoshop);

    RegConsoleCmd("bottest", Command_SayBotTest);

    HookEntityOutput("item_healthkit_full", "OnPlayerTouch", EntityOutput:Entity_OnPlayerTouch);
    HookEntityOutput("item_healthkit_medium", "OnPlayerTouch", EntityOutput:Entity_OnPlayerTouch);
    HookEntityOutput("item_healthkit_small", "OnPlayerTouch", EntityOutput:Entity_OnPlayerTouch);


    // Property Offsets
    g_cloakOffset = FindSendPropInfo("CTFPlayer", "m_flCloakMeter");
    g_wearableOffset = FindSendPropInfo("CTFWearableItem", "m_hOwnerEntity");
    g_shieldOffset = FindSendPropInfo("CTFWearableItemDemoShield", "m_hOwnerEntity");


    // Read/Init the cvars
    AutoExecConfig(true, "sr_medieval");
} // OnPluginStart()


// -----------------------------------------------------------------------------
// Cvar Events
//
public OnCvarChanged(Handle:hCvar, const String:oldValue[], const String:newValue[])
{
    if (hCvar == g_hCvarEnable)                 g_CvarEnable = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldCap)           g_CvarGoldCap = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldCapWitch)      g_CvarGoldCapWitch = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldDomination)    g_CvarGoldDomination = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldRevenge)       g_CvarGoldRevenge = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldAssistKill)    g_CvarGoldAssistKill = StringToInt(newValue);
    else if (hCvar == g_hCvarGoldWitchBounty)   g_CvarGoldWitchBounty = StringToInt(newValue);
    else if (hCvar == g_hCvarShopWitchCost)     g_CvarShopWitchCost = StringToFloat(newValue);

} // OnCvarChanged()


// -----------------------------------------------------------------------------
// Game Events
//

// -----------------------------------------------------------------------------
// OnClientPutInServer()
//
public OnClientPutInServer(ClientID)
{
    if (!g_CvarEnable) return;
    if (g_Debug) PrintToServer("[MF] OnClientPutInServer(%L)", ClientID);

    // Initialize player info and inventory
    IsPlayerAWitch[ClientID] = 0;
    PlayerBounty[ClientID] = 0;
    PlayerGoldCount[ClientID] = 1;
    PlayerAutoBuy[ClientID] = 0;

    for (new j=0; j<MAX_POTIONS; j++)
    {
        PlayerPotions[ClientID][j] = 0;
    }
} // OnClientPutInServer()


// -----------------------------------------------------------------------------
// Event OnGameFrame
//
// Per Frame Updates. Used to hack the speed potion by ensuring speed is reset
// to potion speed (400) every frame as it prematurely ends under a number of
// conditions, including taking damage.
// -----------------------------------------------------------------------------
public OnGameFrame()
{
    for (new i=1; i<=MaxClients; i++)
    {
        if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientObserver(i) ) continue;

        if (PlayerEffectTracker[i][PLAYER_STATUS])
        {
            if(PlayerEffectTracker[i][PLAYER_EFFECT] == POTION_SPEED)
            {
                SetEntPropFloat(i, Prop_Send, "m_flMaxspeed", 400.0);
            }

            if(PlayerEffectTracker[i][PLAYER_EFFECT] == POTION_INVULN)
            {
                if (! ((TF2_GetPlayerConditionFlags(i) & 5) == 5))
                    TF2_AddCondition(i, TFCond_Ubercharged, 20.0);
            }
        }
        new cond = TF2_GetPlayerConditionFlags(i);
        if ((cond & 4096 == 4096)/* || cond == 4100 || cond == 4104 ||*/)
        {
            PlayerEffectTracker[i][PLAYER_FLAG_AUTOCRIT] &= ~PLAYER_FLAG_AUTOCRIT;
        }
        else
        {
            PlayerEffectTracker[i][PLAYER_FLAG_AUTOCRIT] |= PLAYER_FLAG_AUTOCRIT;
        }

        /*new cond =TF2_GetPlayerConditionFlags(i);
        if (GetClientTeam(i)>1)
        {
            if (cond  & 8192 || cond & 32768 )
            {
                if (! ((TF2_GetPlayerConditionFlags(i) & 5) == 5))
                {
                    TF2_AddCondition(i, TFCond_Ubercharged,20.0);
                }
            }
        }*/


        // Delayed by 1 frame so you don't get healed
        if ((PlayerEffectTracker[i][PLAYER_FLAG] & PLAYER_FLAG_BURNME) == PLAYER_FLAG_BURNME)
        {
            PlayerEffectTracker[i][PLAYER_FLAG] &= ~PLAYER_FLAG_BURNME;
            TF2_IgnitePlayer(i, i);
        }
    }
} // OnGameFrame()


// -----------------------------------------------------------------------------
// Event_PlayerSpawn()
//
public Action:Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return Plugin_Continue;

    // Player information
    new UserID = GetEventInt(event, "userid");
    new ClientID = GetClientOfUserId(UserID);

    if (g_Debug)
    {
        decl String:PlayerName[64];
        decl String:ClassName[64];
        new PlayerTeam = GetClientTeam(ClientID);
        GetClientName(ClientID, PlayerName, sizeof(PlayerName));
        GetTFClassName(TF2_GetPlayerClass(ClientID), ClassName);
        PrintToServer("[MF] Event_PlayerSpawn(%s(%i), %s, %i)", PlayerName, ClientID, ClassName, PlayerTeam);
    }

    PrintToHUD(ClientID, 255, 255, 255, 3.0, "Medieval Madness!\nModern weapons are witchcraft!\nUse /shop to shop and /drink to use potions.\n/inventory shows your items.");
    PrintHintText(ClientID, "You have %i gold.", PlayerGoldCount[ClientID]);
    CleanPlayer(ClientID);

    return Plugin_Continue;
} // Event_PlayerSpawn()


// -----------------------------------------------------------------------------
// Event_PlayerBuildObject()
//
public Action:Event_PlayerBuiltObject(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return Plugin_Continue;

    // Player information
    new userid = GetEventInt(event, "userid");
    new ClientID = GetClientOfUserId(userid);
    // new object = GetEventInt(event, "object");
    new index = GetEventInt(event, "index");

    if (IsValidEdict(index))
    {
        decl String:ObjClassName[32];
        GetEdictClassname(index, ObjClassName, sizeof(ObjClassName));

        if (StrEqual(ObjClassName, "obj_sentrygun"))
        {
            SetVariantInt(9999);
            AcceptEntityInput(index, "RemoveHealth");
        }
        /*
        else if (StrEqual(ObjClassName, "obj_dispenser"))
        else if (StrEqual(ObjClassName, "obj_teleporter"))
        */

        if (g_Debug)
        {
            decl String:PlayerName[64];
            GetClientName(ClientID, PlayerName, sizeof(PlayerName));
            PrintToServer("[MF] Event_PlayerBuildObject(%s(%i), %s)", PlayerName, ClientID, ObjClassName);
        }
    } // is valid entity

    return Plugin_Continue;
} // Event_PlayerBuildObject()


// -----------------------------------------------------------------------------
// Entity_OnPlayerTouch()
//
public Action:Entity_OnPlayerTouch(const String:output[], caller, activator, Float:delay)
{
    if (!g_CvarEnable) return Plugin_Continue;

    if (activator > 0)
    {
        if (!IsClientInGame(activator) || !IsPlayerAlive(activator))
        {
            return Plugin_Continue;
        }

        decl String:QueryName[64];
        GetClientName(activator, QueryName, sizeof(QueryName));

        if (IsPlayerAWitch[activator])
        {
            PlayerEffectTracker[activator][PLAYER_FLAG] |= PLAYER_FLAG_BURNME;
            PrintToHUD(activator, 255, 255, 255, 3.0, "Ugh, the health, it burns!!!");
            PrintToChat(activator, "As a witch, healthpacks burn you!");
        }
    }

    return Plugin_Continue;
} // Entity_OnPlayerTouch()


// -----------------------------------------------------------------------------
// Event_RoundStart()
//
public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return Plugin_Continue;

    for (new i=0; i<(MAXPLAYERS+1); i++)
    {
        CleanPlayer(i);
        SetPlayerWitch(i,0);
        PlayerGoldCount[i] = 1;
        PlayerBounty[i] = 0;
        for (new j =0; j<6; j++)
        {
            PlayerPotions[i][j] = 0;
        }
    }

    return Plugin_Continue;
} // Event_RoundStart()


// -----------------------------------------------------------------------------
// Event_PointCaptured()
//
public Event_PointCaptured(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return;

    decl String:cappers[MAXPLAYERS+1] = "";
    if (GetEventString(event,"cappers", cappers, MAXPLAYERS) > 0)
    {
        new len = strlen(cappers);
        for(new i=0;i<len;i++)
        {
            new index  = cappers{i};

            if (IsFakeClient(index) || !IsClientInGame(index))
            {
                continue;
            }

            if (IsPlayerAWitch[index] == 0)
            {
                AddGold(index, g_CvarGoldCap);
                PrintHintText(index, "Point Captured, +%i gold awarded.", g_CvarGoldCap);
            }
            else
            {
                AddGold(index, g_CvarGoldCapWitch);
                PrintHintText(index, "Point Captured using illegal sorcery, +%i gold.", g_CvarGoldCapWitch);
            }
        }
    }
} // Event_PointCaptured()


// -----------------------------------------------------------------------------
// Event_PlayerHurt()
//
public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return Plugin_Continue;

    // Player information
    new userid      = GetEventInt(event, "userid");
    new attacker    = GetEventInt(event, "attacker");
    new weaponid    = GetEventInt(event, "weaponid");
    //new health      = GetEventInt(event, "health");
    new VictimID    = GetClientOfUserId(userid);
    new AttackerID  = GetClientOfUserId(attacker);

    // Attacker Info
    decl String:AttackerName[64];
    GetClientName(AttackerID, AttackerName, sizeof(AttackerName));

    if (g_Debug)
    {
        // Victim Info
        decl String:VictimName[64];
        GetClientName(VictimID, VictimName, sizeof(VictimName));

        // Weapon Info
        decl String:WeaponName[64] = "???";
        GetWeaponName(weaponid, WeaponName, sizeof(WeaponName));
        new damageamount = GetEventInt(event, "damageamount");
        PrintToServer("[MF] Event_PlayerHurt(%s(%i) -> %s(%i) -> %s(%i) = %i damage", AttackerName, AttackerID, WeaponName, weaponid, VictimName, VictimID, damageamount);
    }

    if (
        (AttackerID != 0)                   // Not world
        && (AttackerID != VictimID)         // Not damaging themselves from whatever
       )
    {
        if (!IsWeaponAllowed(weaponid)) // Was hurt using an illegal weapon
        {

            // Has not been flagged as a witch
            if (IsPlayerAWitch[AttackerID] == 0)
            {
                SetPlayerWitch(AttackerID,1);

            }
            // already flagged as a witch, no need to redo this

        } // hurt by illegal weapon
        else
        {
            // Flame potion ignites
            // Axtinguisher ignites (weapon 4 and weapnlevel>1)
            // Witches ignite from any melee weapons
            new bIgnite = ( /*(IsPlayerAWitch[VictimID] == 1 &&
                            ((weaponid != 25) && (weaponid != 57))) ||*/
                            (PlayerEffectTracker[AttackerID][PLAYER_STATUS] == 1 &&  PlayerEffectTracker[AttackerID][PLAYER_EFFECT] == POTION_FLAME));

            if (bIgnite == 0)
            {
                if (weaponid == 4)
                {
                    if (GetRandomInt(0,1) == 1 || IsPlayerAWitch[VictimID])
                    {
                        bIgnite = 1;
                    }
                }
            }

            if (bIgnite == 1)
            {
                TF2_IgnitePlayer(VictimID, VictimID);
            }

            decl String:WeaponName[64] = "???";
            GetWeaponName(weaponid, WeaponName, sizeof(WeaponName));
            if (weaponid == 9)
            {
                new weaponLevel = GetEntProp (GetPlayerWeaponSlot(AttackerID,2), Prop_Send, "m_iEntityLevel");
                if (weaponLevel == 1)
                {
                    if (GetRandomInt(0,2) == 1  || IsPlayerAWitch[VictimID])
                    {
                        TF2_StunPlayer(VictimID, 3.0, 3.0, TF_STUNFLAG_GHOSTEFFECT|TF_STUNFLAG_THIRDPERSON|TF_STUNFLAG_SLOWDOWN, AttackerID);
                    }
                }
            }

            if (weaponid == 1)
            {
                if (GetRandomInt(0,9) <4 || IsPlayerAWitch[VictimID])
                {
                   TF2_StunPlayer(VictimID, 3.0, 3.0,TF_STUNFLAG_THIRDPERSON|TF_STUNFLAG_SLOWDOWN, AttackerID);
                }

            }

        } // hurt by legal weapon
    } // hurt by another player

    return Plugin_Continue;
} // Event_PlayerHurt()


// -----------------------------------------------------------------------------
// Event_PlayerDeath()
//
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
    if (!g_CvarEnable) return Plugin_Continue;

    // Player information
    new userid      = GetEventInt(event, "userid");
    new attacker    = GetEventInt(event, "attacker");
    new assister    = GetEventInt(event, "assister");
    new weaponid    = GetEventInt(event, "weaponid");

    new customkill  = GetEventInt(event, "customkill");
    new flags       = GetEventInt(event, "death_flags");
    new stunflags   = GetEventInt(event, "stun_flags");

    new VictimID    = GetClientOfUserId(userid);
    new AttackerID  = GetClientOfUserId(attacker);
    new AssisterID  = GetClientOfUserId(assister);

    new isDomination        = flags & TF_DEATHFLAG_KILLERDOMINATION;
    new isAssistDomination  = flags & TF_DEATHFLAG_ASSISTERDOMINATION;
    new isRevenge           = flags & TF_DEATHFLAG_KILLERREVENGE;
    new isAssistRevenge     = flags & TF_DEATHFLAG_ASSISTERREVENGE;
    new isFakeKill          = flags & TF_DEATHFLAG_DEADRINGER;

    new bDropItem = 0;

    // Attacker Info
    decl String:AttackerName[64];
    GetClientName(AttackerID, AttackerName, sizeof(AttackerName));

    // Victim Info
    decl String:VictimName[64];
    GetClientName(VictimID, VictimName, sizeof(VictimName));

    // Assister Info
    decl String:AssisterName[64];
    GetClientName(AssisterID, AssisterName, sizeof(AssisterName));


    if (g_Debug)
    {
        // Weapon info
        new String:weapon[64];
        GetEventString(event, "weapon", weapon, sizeof(weapon));

        new String:weaponlog[64];
        GetEventString(event, "weapon_logclassname", weaponlog, sizeof(weaponlog));
        new damagebits = GetEventInt(event, "damagebits");

        decl String:VictimEntityName[32];
        new victim_entindex = GetEventInt(event, "victim_entindex");
        decl String:InfEntityName[32];
        new inflictor_entindex = GetEventInt(event, "inflictor_entindex");

        // Entity information
        if ((inflictor_entindex != 0) && IsValidEdict(inflictor_entindex))
        {
            GetEdictClassname(inflictor_entindex, InfEntityName, sizeof(InfEntityName));
        }
        if ((victim_entindex != 0) && IsValidEdict(victim_entindex))
        {
            GetEdictClassname(victim_entindex, VictimEntityName, sizeof(VictimEntityName));
        }

        PrintToServer("[MF] Event_PlayerDeath(%s(%i) -> %s(%i, %s) -> %s(%i) = %i", AttackerName, AttackerID, weapon, weaponid, weaponlog, VictimName, VictimID, damagebits);
        PrintToServer("[MF]     Assisted by: %s(%i)", AssisterName, AssisterID);
        PrintToServer("[MF]     Entities: %s(%i) on %s(%i)", InfEntityName, inflictor_entindex, VictimEntityName, victim_entindex);
        PrintToServer("[MF]     death_flags: %i, stun_flags: %i, customkill: %i", flags, stunflags, customkill);
    } // kill debug info

    if (
        (AttackerID != 0)                   // Not world
        && (AttackerID != VictimID)         // Not damaging themselves
       )
    {
        new bool:WasLegalKill = false;

        if (isFakeKill)
        {
            PrintHintText(AttackerID, "Killed '%s' for +%d gold", VictimName, GetRandomInt(1,3));
            return Plugin_Continue;
        }
        else if (customkill == 33) // bleeding from tribalkukri
        {

        }
        else if ((customkill == 3) && (TF2_GetPlayerClass(AttackerID) != TFClass_Pyro)) // killed by afterburn, and not a pyro
        {
            WasLegalKill = true;
        }
        else if (IsWeaponAllowed(weaponid)) // allowed weapon
        {
            WasLegalKill = true;
        }

        if (WasLegalKill == false) // Was hurt using an illegal weapon
        {
            if (IsPlayerAWitch[AttackerID] == 0)
            {
                SetPlayerWitch(AttackerID,1);
            }

            new gold = 1+PlayerGoldCount[VictimID]/2;
            if (gold < 1)
            {
                gold = 1;
            }

            // Bonus for Domination/Revenge
            if (isDomination) gold = gold + g_CvarGoldDomination;
            if (isRevenge) gold = gold + g_CvarGoldRevenge;

            // If the target is not a witch, it's a crime
            if (IsPlayerAWitch[VictimID] == 0)
            {
                PlayerBounty[AttackerID] = PlayerBounty[AttackerID] + gold;
                if (IsPlayerAWitch[AttackerID] == 1)
                {
                    PrintToHUD(AttackerID, 200, 150, 0, 2.0, "The bounty on your head has increased to %d", PlayerBounty[AttackerID]);
                }
                PrintToHUDAllBut(AttackerID, 200, 150, 0, 2.0, "%s's bounty has increased to %d!", AttackerName, PlayerBounty[AttackerID]);
                AddGold(AttackerID, gold);
            }
            else
            {
                AddGold(AttackerID, gold);
                PrintHintText(AttackerID, "Killed fellow witch '%s' +%d gold.", VictimName, gold);
            }
        } // killed by illegal weapon
        else // killed by legal weapon
        {
            new gold = 1+PlayerGoldCount[VictimID]/2;
            if (gold < 1)
            {
                gold = 1;
            }

            // Bonus for Domination/Revenge
            if (isDomination) gold = gold + g_CvarGoldDomination;
            if (isRevenge) gold = gold + g_CvarGoldRevenge;

            if (IsPlayerAWitch[VictimID] == 1)
            {
                gold = gold + PlayerBounty[VictimID];
                if (customkill == 3)
                {
                    gold = gold+1;
                    PrintHintText(AttackerID, "Burned the witch '%s' - +%d gold", VictimName, gold);
                }
                else
                {
                    PrintHintText(AttackerID, "Collected Bounty on '%s', +%d gold.", VictimName, gold);
                }
                PlayerBounty[VictimID] = 1;
            }
            else
            {
                PrintHintText(AttackerID, "Killed '%s' for +%d gold", VictimName, gold);
            }
            AddGold(AttackerID, gold);

            // Assister bonus - only for a legal kill, a regular player helping a witch kill someone gets nothing
            if (
                (AssisterID != 0)                           // Was assisted by someone
                && (
                    IsPlayerAWitch[AssisterID] == 0         // Assister is not a witch
                    || (
                        IsPlayerAWitch[AssisterID] == 1     // Or, assister is a witch as is the victim
                        && IsPlayerAWitch[VictimID] == 1
                       )
                   )
               )
            {
                new assistgold = g_CvarGoldAssistKill;
                if (isAssistDomination) assistgold = assistgold + g_CvarGoldDomination;
                if (isAssistRevenge) assistgold = assistgold + g_CvarGoldRevenge;

                PrintHintText(AssisterID, "+%i gold for assisting against %s.", assistgold, VictimName);
                AddGold(AssisterID, assistgold);
            } // assist kill


            bDropItem = 1;
        } // killed by legal weapon


        // Does the victim drop anything?
        if (bDropItem ==1)
        {
            new itemToDrop = GetRandomInt(0, MAX_POTIONS-1);
            if (PlayerPotions[VictimID][itemToDrop]>0)
            {
                PlayerPotions[AttackerID][itemToDrop] = PlayerPotions[AttackerID][itemToDrop] + 1;
                PrintToChat(AttackerID, "%s dropped a %s.", VictimName, g_StoreInventory[itemToDrop]);
                PrintToChat(VictimID, "%s looted a %s. off your corpse", AttackerName, g_StoreInventory[itemToDrop]);
                PlayerPotions[VictimID][itemToDrop] = PlayerPotions[AttackerID][itemToDrop] + 1;
            }
        } // chance to loot potions

        ProcessDeathGold(VictimID);
    } // killed by another player

    // We remove the witch flag here as only death will redeem the player
    ProcessDeath(VictimID);

    return Plugin_Continue;
} // Event_PlayerDeath()


public OnPlayerBecameWitch(client)
{
    if (IsClientInGame(client))
    {
        decl String:ClientName[64];
        GetClientName(client, ClientName, sizeof(ClientName));
        PlayerBounty[client] = g_CvarGoldWitchBounty;
        PrintToHUD(client, 200, 150, 0, 2.0, "Sorcery! You have been flagged as a witch!");
        PrintToHUDAllBut(client, 200, 150, 0, 2.0, "%s is practicing sorcery!  Burn the witch!", ClientName);
        ServerCommand("sm_beacon \"%s\"", ClientName);

        PrintToChat(client, "Use of modern weapons makes you a witch.");
        PrintToChat(client, "Witches pay more to /shop and burn when touching healthkits.");
        PrintToChat(client, "Use /repent to repent... for a price.");
        new  gold = 0;
        for (new j=0; j<MAX_POTIONS; j++)
        {
            gold += g_StorePrices[j] * PlayerPotions[client][j];
            PlayerPotions[client][j] = 0;
        }
        AddGold(client, gold);

    }
}

public OnPlayerRepent(client)
{
    decl String:ClientName[64];
    GetClientName(client, ClientName, sizeof(ClientName));
    SetPlayerWitch(client,0);
    PrintToHUD(client, 255, 255, 255, 3.0, "Your sins are forgiven, you are righteous again!", ClientName);
    PrintToHUDAllBut(client, 255, 255, 255, 3.0, "Hallelujah - %s has repented for their sins.", ClientName);
    ServerCommand("sm_beacon \"%s\"", ClientName);
}


public SetPlayerWitch(client,isWitch)
{
    if (isWitch != IsPlayerAWitch[client])
    {
        IsPlayerAWitch[client] = isWitch;
        if (isWitch)
        {
            OnPlayerBecameWitch(client);
        }
        else
        {
            OnPlayerRepent(client);
        }
    }
}


// -----------------------------------------------------------------------------
// Functions
//

// GetTFClassName() - get a string name of the TF class
//  TFClassID - TFClass_Type of the class to get
//  TFClassName - string to return via
//  Count - plurals?
//
// Returns the name of the TFClassID
GetTFClassName(TFClassType:TFClassID, String:TFClassName[], Count=0)
{
    decl String:TFClassName2[64];

    switch (TFClassID)
    {
        case TFClass_Unknown :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Unknowns");
                                else Format(TFClassName2, sizeof(TFClassName2), "Unknown");
        case TFClass_Scout   :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Scouts");
                                else Format(TFClassName2, sizeof(TFClassName2), "Scout");
        case TFClass_Soldier :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Soldiers");
                                else Format(TFClassName2, sizeof(TFClassName2), "Soldier");
        case TFClass_Pyro    :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Pyros");
                                else Format(TFClassName2, sizeof(TFClassName2), "Pyro");
        case TFClass_DemoMan :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Demomen");
                                else Format(TFClassName2, sizeof(TFClassName2), "Demoman");
        case TFClass_Heavy   :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Heavies");
                                else Format(TFClassName2, sizeof(TFClassName2), "Heavy");
        case TFClass_Medic   :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Medics");
                                else Format(TFClassName2, sizeof(TFClassName2), "Medic");
        case TFClass_Engineer:  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Engineers");
                                else Format(TFClassName2, sizeof(TFClassName2), "Engineer");
        case TFClass_Sniper  :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Snipers");
                                else Format(TFClassName2, sizeof(TFClassName2), "Sniper");
        case TFClass_Spy     :  if (Count > 1) Format(TFClassName2, sizeof(TFClassName2), "Spies");
                                else Format(TFClassName2, sizeof(TFClassName2), "Spy");
    }
    Format(TFClassName, sizeof(TFClassName2), TFClassName2);
} // GetTFClassName()


// PrintToHUD()
public PrintToHUDAll(Red, Green, Blue, Float:Duration, const String:Message[], any:...)
{
    new String:FormattedMessage[256];
    VFormat(FormattedMessage, sizeof(FormattedMessage), Message, 6);

    SetHudTextParams(-1.0, 0.2,    // Screen X,Y, -1 for center
                     Duration,      // Hold time
                     Red,           // R
                     Green,         // G
                     Blue,          // B
                     255,           // A
                     2,             // Effect, 1 = fade in/out, 2 = flash one char at a time
                     0.5,           // Duration of chosen effect (may not apply to all effects).
                     0.01,          // Number of seconds to spend fading in
                     0.2            // Number of seconds to spend fading out
                    );

    for (new i=1; i<MaxClients; i++)
    {
        if (IsClientInGame(i))
        {
            if (IsFakeClient(i))
            {
                continue;
            }
            else
            {
                ShowSyncHudText(i, g_hHud, FormattedMessage);
            }
        }
    }
} // PrintToHUDAll()


public PrintToHUDAllBut(SkipPlayerID, Red, Green, Blue, Float:Duration, const String:Message[], any:...)
{
    new String:FormattedMessage[256];
    VFormat(FormattedMessage, sizeof(FormattedMessage), Message, 7);

    SetHudTextParams(-1.0, 0.2,    // Screen X,Y, -1 for center
                     Duration,      // Hold time
                     Red,           // R
                     Green,         // G
                     Blue,          // B
                     255,           // A
                     2,             // Effect, 1 = fade in/out, 2 = flash one char at a time
                     0.5,           // Duration of chosen effect (may not apply to all effects).
                     0.01,          // Number of seconds to spend fading in
                     0.2            // Number of seconds to spend fading out
                    );

    for (new i=1; i<MaxClients; i++)
    {
        if (IsClientInGame(i))
        {
            if (IsFakeClient(i)) // bot
            {
                continue;
            }
            if (i != SkipPlayerID)
            {
                ShowSyncHudText(i, g_hHud, FormattedMessage);
            }
        }
    }
} // PrintToHUDAllBut()


public PrintToHUD(ClientID, Red, Green, Blue, Float:Duration, const String:Message[], any:...)
{
    new String:FormattedMessage[256];
    VFormat(FormattedMessage, sizeof(FormattedMessage), Message, 7);

    SetHudTextParams(-1.0, 0.2,    // Screen X,Y, -1 for center
                     Duration,      // Hold time
                     Red,           // R
                     Green,         // G
                     Blue,          // B
                     255,           // A
                     2,             // Effect, 1 = fade in/out, 2 = flash one char at a time
                     0.5,           // Duration of chosen effect (may not apply to all effects).
                     0.01,          // Number of seconds to spend fading in
                     0.2            // Number of seconds to spend fading out
                    );

    if (IsClientInGame(ClientID) && !IsFakeClient(ClientID))
    {
        ShowSyncHudText(ClientID, g_hHud, FormattedMessage);
    }
} // PrintToHUDAllBut()


public GetWeaponName(weaponid, String:WeaponName[], WeaponNameSize)
{
    switch (weaponid)
    {
        /*
        case : Format(WeaponName, WeaponNameSize, "");
        */
        case 0  : Format(WeaponName, WeaponNameSize, "world");                      // or sandman ball
        case 1  : Format(WeaponName, WeaponNameSize, "tf_weapon_bat");
        case 2  : Format(WeaponName, WeaponNameSize, "tf_weapon_sandman");
        case 3  : Format(WeaponName, WeaponNameSize, "tf_weapon_bottle");
        case 4  : Format(WeaponName, WeaponNameSize, "tf_weapon_fireaxe");
        case 5  : Format(WeaponName, WeaponNameSize, "tf_weapon_club");             // Kukri
        case 7  : Format(WeaponName, WeaponNameSize, "tf_weapon_knife");
        case 8  : Format(WeaponName, WeaponNameSize, "tf_weapon_fists");
        case 9  : Format(WeaponName, WeaponNameSize, "tf_weapon_shovel");
        case 10 : Format(WeaponName, WeaponNameSize, "tf_weapon_wrench");
        case 11 : Format(WeaponName, WeaponNameSize, "tf_weapon_bonesaw");
        case 12 : Format(WeaponName, WeaponNameSize, "tf_weapon_shotgun_primary");  // engineer
        case 13 : Format(WeaponName, WeaponNameSize, "tf_weapon_shotgun_soldier");
        case 14 : Format(WeaponName, WeaponNameSize, "tf_weapon_shotgun_hwg");
        case 15 : Format(WeaponName, WeaponNameSize, "tf_weapon_shotgun_pyro");
        case 16 : Format(WeaponName, WeaponNameSize, "tf_weapon_scattergun");
        case 17 : Format(WeaponName, WeaponNameSize, "tf_weapon_sniperrifle");
        case 18 : Format(WeaponName, WeaponNameSize, "tf_weapon_minigun");
        case 19 : Format(WeaponName, WeaponNameSize, "tf_weapon_smg");
        case 20 : Format(WeaponName, WeaponNameSize, "tf_weapon_syringegun_medic");
        case 22 : Format(WeaponName, WeaponNameSize, "tf_weapon_rocketlauncher");
        case 23 : Format(WeaponName, WeaponNameSize, "tf_weapon_pipebomb");
        case 24 : Format(WeaponName, WeaponNameSize, "tf_weapon_remotepipe");
        case 25 : Format(WeaponName, WeaponNameSize, "tf_weapon_flamethrower");
        case 35 : Format(WeaponName, WeaponNameSize, "tf_weapon_pipebomblauncher");
        case 40 : Format(WeaponName, WeaponNameSize, "tf_weapon_pistol");
        case 41 : Format(WeaponName, WeaponNameSize, "tf_weapon_pistol_scout");
        case 42 : Format(WeaponName, WeaponNameSize, "tf_weapon_revolver");
        case 52 : Format(WeaponName, WeaponNameSize, "tf_weapon_grenadelauncher");
        case 57 : Format(WeaponName, WeaponNameSize, "tf_weapon_flaregun");
        case 59 : Format(WeaponName, WeaponNameSize, "jarate/bleeding");
        case 60 : Format(WeaponName, WeaponNameSize, "tf_weapon_compound_bow");
        case 63 : Format(WeaponName, WeaponNameSize, "tf_weapon_sword");
        case 64 : Format(WeaponName, WeaponNameSize, "tf_weapon_rocketlauncher_directhit");

        default : Format(WeaponName, WeaponNameSize, "unknown");
    } // switch
} // GetWeaponName()


public IsWeaponAllowed(weaponid)
{
    new WeaponAllowed = true;
    switch (weaponid)
    {
        case 0  : WeaponAllowed = true;     // world / sandman ball
        case 1  : WeaponAllowed = true;     // tf_weapon_bat
        case 2  : WeaponAllowed = true;     // tf_weapon_sandman
        case 3  : WeaponAllowed = true;     // tf_weapon_bottle
        case 4  : WeaponAllowed = true;     // tf_weapon_fireaxe
        case 5  : WeaponAllowed = true;     // tf_weapon_club/kukri
        case 7  : WeaponAllowed = true;     // tf_weapon_knife
        case 8  : WeaponAllowed = true;     // tf_weapon_fists
        case 9  : WeaponAllowed = true;     // tf_weapon_shovel
        case 10 : WeaponAllowed = true;     // tf_weapon_wrench
        case 11 : WeaponAllowed = true;     // tf_weapon_bonesaw

        case 12 : WeaponAllowed = false;    // tf_weapon_shotgun_primary  // engineer
        case 13 : WeaponAllowed = false;    // tf_weapon_shotgun_soldier
        case 14 : WeaponAllowed = false;    // tf_weapon_shotgun_hwg
        case 15 : WeaponAllowed = false;    // tf_weapon_shotgun_pyro
        case 16 : WeaponAllowed = false;    // tf_weapon_scattergun
        case 17 : WeaponAllowed = false;    // tf_weapon_sniperrifle
        case 18 : WeaponAllowed = false;    // tf_weapon_minigun
        case 19 : WeaponAllowed = false;    // tf_weapon_smg
        case 20 : WeaponAllowed = false;    // tf_weapon_syringegun_medic
        case 22 : WeaponAllowed = false;    // tf_weapon_rocketlauncher
        case 23 : WeaponAllowed = false;    // tf_weapon_pipebomb
        case 24 : WeaponAllowed = false;    // tf_weapon_remotepipe
        case 25 : WeaponAllowed = false;    // tf_weapon_flamethrower
        case 35 : WeaponAllowed = false;    // tf_weapon_pipebomblauncher
        case 40 : WeaponAllowed = false;    // tf_weapon_pistol // engineer
        case 41 : WeaponAllowed = false;    // tf_weapon_pistol_scout
        case 42 : WeaponAllowed = false;    // tf_weapon_revolver
        case 52 : WeaponAllowed = false;    // tf_weapon_grenadelauncher
        case 57 : WeaponAllowed = false;    // tf_weapon_flaregun

        case 59 : WeaponAllowed = true;     // jarate + tribal kukri bleeding
        case 60 : WeaponAllowed = true;     // tf_weapon_compound_bow
        case 63 : WeaponAllowed = true;     // tf_weapon_sword

        case 64 : WeaponAllowed = false;    // tf_weapon_rocketlauncher_directhit
    } // switch

    return(WeaponAllowed);
} // IsWeaponAllowed()


// Increments the player's gold
// Check for autobuy potions
public AddGold(client, count)
{
    PlayerGoldCount[client]+=count;
    CheckAutoBuy(client);
} // AddGold()


// Removes gold from the player
public RemoveGold(client, count)
{
    PlayerGoldCount[client]-=count;
} // RemoveGold()


public ProcessDeathGold(client)
{
    if (PlayerGoldCount[client] > 1)
    {

        new lost = 0;
        lost = PlayerGoldCount[client]/3;

        if (PlayerGoldCount[client]==2)
        {
            lost = 1;
            PlayerGoldCount[client] =1;
        }
        else
        {
            PlayerGoldCount[client] = PlayerGoldCount[client]-lost ;
        }

    }
    else
    {
        PlayerGoldCount[client] = 1;
    }
} // ProcessDeathGold()


public ProcessDeath(client)
{
    if (PlayerEffectTracker[client][PLAYER_EFFECT]>0)
    {
        switch (PlayerEffectTracker[client][PLAYER_EFFECT])
        {
            case POTION_INVISIBILITY:
            {
                Colorize(client, NORMAL);
            }


        } // switch
    }



} // ProcessDeath()

/*
// -----------------------------------------------------------------------------
// TF_AddCond
//
// Hack I found on the sourcemod forums to set player conditions.
// Usually they are only allowed with sv_cheats, so this sets sv_cheats on,
// replicates it, creates a face client command issuing the 'addcond' command
// and resets sv_cheats.
//
// Note that this is probably not safe, people could, through brute force, time
// the use of an uber potion (cond 5) with command spam trying to exploit the
// sv_cheats window. Logging on the server could catch that though.
// -----------------------------------------------------------------------------
stock TF2_AddCond(client, cond)
{
    new Handle:cvar = FindConVar("sv_cheats"), bool:enabled = GetConVarBool(cvar), flags = GetConVarFlags(cvar);
    if (!enabled)
    {
        SetConVarFlags(cvar, flags^FCVAR_NOTIFY^FCVAR_REPLICATED);
        SetConVarBool(cvar, true);
    }
    FakeClientCommand(client, "addcond %i", cond);
    //FakeClientCommand(client, "isLoser");
    if (!enabled)
    {
        SetConVarBool(cvar, false);
        SetConVarFlags(cvar, flags);
    }
} // TF2_AddCond()

// -----------------------------------------------------------------------------
// TF2_RemoveCond
//
// Same deal as TF2_AddCond, just removing conditions
// -----------------------------------------------------------------------------
stock TF2_RemoveCond(client, cond)
{
    new Handle:cvar = FindConVar("sv_cheats"), bool:enabled = GetConVarBool(cvar), flags = GetConVarFlags(cvar);
    if (!enabled)
    {
        SetConVarFlags(cvar, flags^FCVAR_NOTIFY^FCVAR_REPLICATED);
        SetConVarBool(cvar, true);
    }
    FakeClientCommand(client, "removecond %i", cond);
    if (!enabled)
    {
        SetConVarBool(cvar, false);
        SetConVarFlags(cvar, flags);
    }
} // TF2_RemoveCond()
*/

// -----------------------------------------------------------------------------
// CleanPlayer(client)
//
// Lifted and modified from rtd 0.3, this resets any potion effect that might
// be active.
// -----------------------------------------------------------------------------
public CleanPlayer(client)
{
    if (PlayerEffectTracker[client][PLAYER_EFFECT]>0)
    {
        switch (PlayerEffectTracker[client][PLAYER_EFFECT])
        {
            case POTION_INVISIBILITY:
            {
                Colorize(client, NORMAL);
            }

            case POTION_INVULN:
            {
                TF2_RemoveCondition(client, TFCond_Ubercharged);
                //TF2_RemoveCondition(client,5); /*UBER*/
                /*SetGodmode(client, false);
                Colorize(client, NORMAL);*/
            }

            case POTION_SPEED:
            {
                SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", float(PlayerEffectTracker[client][PLAYER_EXTRA2]));
            }

            case POTION_FLIGHT:
            {
                SetEntityGravity(client, 1.0);
            }
        } // switch
    } // has effects

    PlayerEffectTracker[client][PLAYER_STATUS] = 0;
    PlayerEffectTracker[client][PLAYER_EXTRA] = 0;
    PlayerEffectTracker[client][PLAYER_EXTRA2] = 0;
    PlayerEffectTracker[client][PLAYER_EFFECT] = 0;

    ResetTimers(client);

    return;
} // CleanPlayer()


// -----------------------------------------------------------------------------
// Colorize
//
// Apply an overlay / transparency color to the selected client and deal with various
// special cases (e.g. demo shield,eyes).
//
// Used by the invisiblity potion.
// -----------------------------------------------------------------------------
public Colorize(client, color[4])
{
    new maxents = GetMaxEntities();
    // Colorize player and weapons
    new m_hMyWeapons = FindSendPropOffs("CBasePlayer", "m_hMyWeapons");

    for (new i = 0, weapon; i < 47; i += 4)
    {
        weapon = GetEntDataEnt2(client, m_hMyWeapons + i);

        if (weapon > -1 )
        {
            decl String:strClassname[250];
            GetEdictClassname(weapon, strClassname, sizeof(strClassname));
            if(StrContains(strClassname, "tf_weapon") == -1) continue;

            SetEntityRenderMode(weapon, RENDER_TRANSCOLOR);
            SetEntityRenderColor(weapon, color[0], color[1],color[2], color[3]);
        }
    }

    SetEntityRenderMode(client, RENDER_TRANSCOLOR);
    SetEntityRenderColor(client, color[0], color[1], color[2], color[3]);

    // Colorize any wearable items
    for (new i=MaxClients+1; i <= maxents; i++)
    {
        if(!IsValidEntity(i)) continue;

        decl String:netclass[32];
        GetEntityNetClass(i, netclass, sizeof(netclass));

        SetWearablesRGBA_Impl(client, "tf_wearable_item", "CTFWearableItem",color );
        if (strcmp(netclass, "CTFWearableItemDemoShield") == 0)
        {
            if(GetEntDataEnt2(i, g_shieldOffset) == client)
            {
                SetEntityRenderMode(i, RENDER_TRANSCOLOR);
                SetEntityRenderColor(i, color[0], color[1], color[2], color[3]);
            }
        }
    }

    if (TF2_GetPlayerClass(client) == TFClass_Spy)
    {
        new iWeapon = GetEntPropEnt(client, Prop_Send, "m_hDisguiseWeapon");
        if(iWeapon && IsValidEntity(iWeapon))
        {
            SetEntityRenderMode(iWeapon, RENDER_TRANSCOLOR);
            SetEntityRenderColor(iWeapon, color[0], color[1], color[2], color[3]);
        }
    } // spy
    else if (TF2_GetPlayerClass(client)  == TFClass_DemoMan)
    {
        new decapitations = GetEntProp(client, Prop_Send, "m_iDecapitations");
        if(decapitations >= 1)
        {
            if (color[3] > 0) // Removes Glowing Eye
            {
                TF2_RemoveCondition(client, 18);
            }
            else //Add Glowing Eye
            {
                TF2_AddCondition(client, 18, 0.0);
            }
        }
    } // demoman
} // Colorize()


// -----------------------------------------------------------------------------
// SetWearablesRGBA_Impl
//
// Lifted from some random pastebin page that has since disappared, this code
// deals with coloring entities of the specified class on the player model,
// used for the invisiblity/transparency potion.
// -----------------------------------------------------------------------------
SetWearablesRGBA_Impl(client, const String:entClass[], const String:serverClass[], color[4])
{
    new ent = -1;
    while ((ent = FindEntityByClassname(ent, entClass)) != -1)
    {
        if ( IsValidEntity(ent) )
        {
            if (GetEntDataEnt2(ent, FindSendPropOffs(serverClass, "m_hOwnerEntity")) == client)
            {
                SetEntityRenderMode(ent, RENDER_TRANSCOLOR);
                SetEntityRenderColor(ent, color[0], color[1], color[2], color[3]);
            }
        }
        //RemoveEdict(ent);
    } // while
} // SetWearablesRGBA_Impl()


// -----------------------------------------------------------------------------
// CheckSecondTimer
//
// Lifted from rtd 0.3, this function kills any running secondary timers.
// -----------------------------------------------------------------------------
public CheckSecondTimer(client)
{
    // Check to see if the secondary timer is running
    if(PlayerEffectTimers[client][1] != INVALID_HANDLE)
    {
        KillTimer(PlayerEffectTimers[client][1]);
        PlayerEffectTimers[client][1] = INVALID_HANDLE;
    }

    return;
} // CheckSecondTimer()


// -----------------------------------------------------------------------------
// ResetTimers
//
// Lifted from rtd 0.3, this function kills any running timers.
// -----------------------------------------------------------------------------
public ResetTimers(client)
{
    if(PlayerEffectTimers[client][0] != INVALID_HANDLE)
    {
        KillTimer(PlayerEffectTimers[client][0]);
        PlayerEffectTimers[client][0] = INVALID_HANDLE;
    }

    if(PlayerEffectTimers[client][1] != INVALID_HANDLE)
    {
        KillTimer(PlayerEffectTimers[client][1]);
        PlayerEffectTimers[client][1] = INVALID_HANDLE;
    }

    return;
} // ResetTimers()


// Sorts a 2-element array by the second element, for player list sorting
public Sort2DArray(elem1[], elem2[], const array[][], Handle:hndl)
{
    if (elem1[1] > elem2[1])
    {
        return -1;
    }
    else if (elem1[1] < elem2[1])
    {
        return 1;
    }
    return 0;
} // Sort2DArray()

// -----------------------------------------------------------------------------
// Commands
//
public GetItemCost(client, item)
{
    new ItemCost = g_StorePrices[item];
    if (IsPlayerAWitch[client])
    {
        ItemCost = RoundFloat(g_StorePrices[item] * g_CvarShopWitchCost);
    }
    return ItemCost;
}

public BuyItem(client, item)
{
    RemoveGold(client,GetItemCost(client,item));
    PlayerPotions[client][item] = PlayerPotions[client][item] +1;
}

public CanBuyItem(client,item)
{
    return PlayerGoldCount[client] >= GetItemCost(client,item);
}

public GetItemFromText(String:text[192])
{
    new item = -1;


    if (text[0] == '1')
    {
        item = POTION_MINOR_VITALITY;
    }
    else if (text[0] == '2')
    {
        item = POTION_FLIGHT;
    }
    else if (text[0] == '3')
    {
        item = POTION_MAJOR_VITALITY;
    }
    else if (text[0] == '4')
    {
        item = POTION_SPEED;
    }
    else if (text[0] == '5')
    {
        item = POTION_INVISIBILITY;
    }
    else if (text[0] == '6')
    {
        item = POTION_FLAME;
    }
    else if (text[0] == '7')
    {
        item = POTION_CRIT;
    }
    else if (text[0] == '8')
    {
        item = POTION_INVULN;
    }
    return item;
}

public ApplyItemEffect(client,index)
{
    switch (index)
    {
        case POTION_MINOR_VITALITY :
        {
            new health =  GetEntProp(client, Prop_Data,"m_iHealth")+75;

            if (health<550)
            {
                SetEntProp(client, Prop_Data, "m_iHealth", health);
                ReplyToCommand(client, "Used %s (+%d health)", g_StoreInventory[index],75);
                CreateParticle("healhuff_red", 5.0, client);
                CreateParticle("healhuff_blu", 5.0, client);
            }
        }

        case POTION_FLIGHT:
        {
            PlayerEffectTracker[client][PLAYER_EXTRA] = 20;
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;
            SetEntityGravity(client, 0.2);
            PlayerEffectTimers[client][0] = CreateTimer(20.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }

        case POTION_SPEED:
        {
            PlayerEffectTracker[client][PLAYER_EXTRA2] = RoundToFloor(GetEntPropFloat(client, Prop_Send, "m_flMaxspeed"));
            SetEntDataFloat(client, FindSendPropInfo("CTFPlayer", "m_flMaxspeed"), 400.0);
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;
            PlayerEffectTracker[client][PLAYER_EXTRA] = 20;
            PlayerEffectTimers[client][0] = CreateTimer(20.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }

        case POTION_FLAME:
        {
            PlayerEffectTracker[client][PLAYER_EXTRA] = 20;
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;
            PlayerEffectTimers[client][0] = CreateTimer(20.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }


        case POTION_MAJOR_VITALITY :
        {
            new health =  GetEntProp(client, Prop_Data,"m_iHealth") + 150;

            if (health < 550)
            {
                SetEntProp(client, Prop_Data, "m_iHealth", health);
                ReplyToCommand(client, "Used %s (+%d health)", g_StoreInventory[index],150);
                CreateParticle("healhuff_red", 5.0, client);
                CreateParticle("healhuff_blu", 5.0, client);
            }
        }

        case POTION_INVISIBILITY:
        {
            Colorize(client, INVIS);

            PlayerEffectTracker[client][PLAYER_EXTRA] = 20;
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;
            PlayerEffectTimers[client][0] = CreateTimer(20.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }

        case POTION_CRIT:
        {
            PlayerEffectTracker[client][PLAYER_EXTRA] = 15;
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;

            PlayerEffectTimers[client][0] = CreateTimer(15.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }

        case POTION_INVULN:
        {
            //SetGodmode(client, true);
            //Colorize(client, BLACK);
            TF2_AddCondition(client, TFCond_Ubercharged,20.0);

            // Mark that the player is rtd'ing
            PlayerEffectTracker[client][PLAYER_STATUS] = 1;
            PlayerEffectTracker[client][PLAYER_EXTRA] = 20;

            // Setup the timer
            PlayerEffectTimers[client][0] = CreateTimer(20.0, Timer_RemovePlayerEffect, client, TIMER_REPEAT);
            PlayerEffectTimers[client][1] = CreateTimer(1.0, Timer_Countdown, client, TIMER_REPEAT);
        }
    } // switch

    PlayerEffectTracker[client][PLAYER_EFFECT] = index;
    PlayerEffectTracker[client][PLAYER_TIMESTAMP] = GetTime();

} // ApplyEffects()



// -----------------------------------------------------------------------------
// CreateParticle
//
// Create Particle system by specified name on the client. Used for health potion
// particles. Lifted from rtd 0.3
// -----------------------------------------------------------------------------
stock CreateParticle(const String:strType[], Float:flTime, iEntity)
{
    new iParticle = CreateEntityByName("info_particle_system");

    if (!IsValidEdict(iParticle)) return;

    new Float:flPos[3];
    GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", flPos);
    TeleportEntity(iParticle, flPos, NULL_VECTOR, NULL_VECTOR);

    DispatchKeyValue(iParticle, "effect_name", strType);

    SetVariantString("!activator");
    AcceptEntityInput(iParticle, "SetParent", iEntity, iParticle, 0);

    SetVariantString("head");
    AcceptEntityInput(iParticle, "SetParentAttachmentMaintainOffset", iParticle, iParticle, 0);

    DispatchKeyValue(iParticle, "targetname", "particle");

    DispatchSpawn(iParticle);
    ActivateEntity(iParticle);
    AcceptEntityInput(iParticle, "Start");

    CreateTimer(flTime, Timer_DeleteParticle, iParticle);
} // CreateParticle()


// -----------------------------------------------------------------------------
// Action:Timer_DeleteParticle
//
// Remove a particle system from the targeted client.
// -----------------------------------------------------------------------------
public Action:Timer_DeleteParticle(Handle:timer, any:iParticle)
{
    if (IsValidEdict(iParticle))
    {
        decl String:strClassname[50];
        GetEdictClassname(iParticle, strClassname, sizeof(strClassname));

        if(StrEqual(strClassname, "info_particle_system", false))
            RemoveEdict(iParticle);
    }
} // Timer_DeleteParticle()


// -----------------------------------------------------------------------------
// SetGodmode
//
// Alternate approach to godmode that does not rely on the SV_Cheats approach
// Lifted from rtd 0.3, will make this an option via convars.
// -----------------------------------------------------------------------------
public SetGodmode(client, bool:playerState)
{
    if (playerState)
    {
        SetEntProp(client, Prop_Data, "m_takedamage", 0, 1);
        Colorize(client, BLACK);
    }
    else
    {
        SetEntProp(client, Prop_Data, "m_takedamage", 2, 1);
        Colorize(client, NORMAL);
    }

    return;
} // SetGodmode()


// -----------------------------------------------------------------------------
// Action:Timer_RemovePlayerEffect
//
// Lifted from rtd 0.3, this function undoes the effects of potions at the
// expiration of the potion timer.
// -----------------------------------------------------------------------------
public Action:Timer_RemovePlayerEffect(Handle:Timer, any:client)
{
    if (!IsClientInGame(client))
    {
        PlayerEffectTimers[client][0] = INVALID_HANDLE;
        return Plugin_Handled;
    }

    if (PlayerEffectTracker[client][PLAYER_EFFECT] > 0)
    {
        switch (PlayerEffectTracker[client][PLAYER_EFFECT])
        {
            case POTION_INVISIBILITY:
            {
                Colorize(client, NORMAL);
            }

            case POTION_INVULN:
            {
                TF2_RemoveCondition(client, TFCond_Ubercharged);
                /*SetGodmode(client, false);
                Colorize(client, NORMAL);*/
            }

            case POTION_SPEED:
            {
                SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", float(PlayerEffectTracker[client][PLAYER_EXTRA2]));
            }

            case POTION_FLIGHT:
            {
                SetEntityGravity(client, 1.0);
            }
        } // switch
    } // effect running on player


    PlayerEffectTracker[client][PLAYER_STATUS] = 0;
    PlayerEffectTracker[client][PLAYER_EFFECT] = 0;
    PlayerEffectTracker[client][PLAYER_EXTRA2] = 0;

    // Set a new timestamp
    PlayerEffectTracker[client][PLAYER_TIMESTAMP] = GetTime();
    CheckSecondTimer(client);
    PlayerEffectTimers[client][0] = INVALID_HANDLE;

    return Plugin_Stop;
} // Timer_RemovePlayerEffect()


// -----------------------------------------------------------------------------
// CountDown Timer
//
// Lifted from rtd 0.3. Used to dispay a timer in the center of the screen
// showing the remaining time and name of the currently used potion.
//
// Uses data in PlayerEffectTracker[client][PLAYER_EXTRA] to count down.
// -----------------------------------------------------------------------------
public Action:Timer_Countdown(Handle:timer, any:client)
{
    if (!IsClientInGame(client) || !IsPlayerAlive(client)) return Plugin_Stop;
    if (!PlayerEffectTracker[client][PLAYER_STATUS]) return Plugin_Stop;

    PlayerEffectTracker[client][PLAYER_EXTRA]--;
    PrintCenterText(client, "%s (%ds) ", g_StoreInventory[PlayerEffectTracker[client][PLAYER_EFFECT]], PlayerEffectTracker[client][PLAYER_EXTRA]);

    return Plugin_Continue;
} // Timer_Countdown()


// -----------------------------------------------------------------------------
// Action:TF2_CalcIsAttackCritical
//
// Override TF2 Critical Calculation, used by the Crit Potion
// -----------------------------------------------------------------------------
public Action:TF2_CalcIsAttackCritical(client, weapon, String:weaponname[], &bool:result)
{
    if (!g_CvarEnable) return Plugin_Continue;

    if (!PlayerEffectTracker[client][PLAYER_STATUS]) return Plugin_Continue;

    if (PlayerEffectTracker[client][PLAYER_EFFECT] == POTION_CRIT)
    {
        result = true;
        return Plugin_Handled;
    }

    if ((PlayerEffectTracker[client][PLAYER_FLAG] & PLAYER_FLAG_AUTOCRIT) == PLAYER_FLAG_AUTOCRIT)
    {
        result=true;
        return Plugin_Handled;
    }

    return Plugin_Continue;
} // TF2_CalcIsAttackCritical()


// -----------------------------------------------------------------------------
// Command Gold
//
public Action:Command_SayGold(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    if (args > 0)
    {
        new HighestGold[MAXPLAYERS+1][2];
        new HighestBounty[MAXPLAYERS+1][2];
        new i, HighestGoldCount, HighestBountyCount;
        decl String:PlayerName[64];

        for (i=1; i<=MaxClients; i++)
        {
            if (IsClientInGame(i)) // assign their points to arrays to be sorted
            {
                if (PlayerGoldCount[i] > 0)
                {
                    HighestGold[HighestGoldCount][0] = i;
                    HighestGold[HighestGoldCount][1] = PlayerGoldCount[i];
                    HighestGoldCount++;
                }
                if (PlayerBounty[i] > 0)
                {
                    HighestBounty[HighestBountyCount][0] = i;
                    HighestBounty[HighestBountyCount][1] = PlayerBounty[i];
                    HighestBountyCount++;
                }
            }
        }

        SortCustom2D(HighestGold, HighestGoldCount, Sort2DArray);
        SortCustom2D(HighestBounty, HighestBountyCount, Sort2DArray);

        if (HighestGoldCount > 3) HighestGoldCount = 3;
        for (i=0; i<HighestGoldCount; i++)
        {
            new ClientID = HighestGold[i][0];
            GetClientName(ClientID, PlayerName, sizeof(PlayerName));
            ReplyToCommand(client, "Most Gold %i: %16s %2i gold, %2i bounty.", i+1, PlayerName, PlayerGoldCount[ClientID], PlayerBounty[ClientID]);
        }

        if (HighestBountyCount > 3) HighestBountyCount = 3;
        for (i=0; i<HighestBountyCount; i++)
        {
            new ClientID = HighestBounty[i][0];
            GetClientName(ClientID, PlayerName, sizeof(PlayerName));
            ReplyToCommand(client, "Most Bounty %i: %16s %2i bounty, %2i gold.", i+1, PlayerName, PlayerBounty[ClientID], PlayerGoldCount[ClientID]);
        }

        ReplyToCommand(client, "See console for complete player list.");
        PrintToConsole(client, "[MF] Complete player gold and bounty list:");
        for (i=1; i<=MaxClients; i++)
        {
            if (IsClientInGame(i))
            {
                GetClientName(i, PlayerName, sizeof(PlayerName));
                PrintToConsole(client, "  %2i. %20s (%2d gold, %2d bounty)", i, PlayerName, PlayerGoldCount[i], PlayerBounty[i]);
            }
        }
    }
    else
    {
        if (IsPlayerAWitch[client] == 1)
        {
            PrintHintText(client, "You are a witch. You have %d gold and there is a bounty of %d gold on your head.", PlayerGoldCount[client], PlayerBounty[client]);
        }
        else
        {
            PrintHintText(client, "You have %d gold.", PlayerGoldCount[client]);
        }
    }

    return Plugin_Handled;
} // Command_SayGold()


// -----------------------------------------------------------------------------
// Command Inventory
//
public Action:Command_SayInventory(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    //PlayerGoldCount[client] = 1000;
    for (new i=0; i<MAX_POTIONS; i++)
    {
        ReplyToCommand(client, "%d %s (x%d)", i+1, g_StoreInventory[i], PlayerPotions[client][i]);
    }
    return Plugin_Handled;
} // Command_SayInventory()


// -----------------------------------------------------------------------------
// Command Shop
//
public ShopMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
    if (action == MenuAction_Select) // If an option was selected, buy the potion (if possible)
    {
        new String:info[32];
        GetMenuItem(menu, param2, info, sizeof(info));

        new client = param1;
        new item = StringToInt(info);

        // Param1 = client
        // Param2 = menu #, does not always correspond to the list index due to pages
        // info = string of the menu info, which we set as the list index # (and convert to integer)
        if  (!CanBuyItem(client, item))
        {
            ReplyToCommand(client, "You can not afford %s.", g_StoreInventory[item]);
        }
        else
        {
            BuyItem(client,item);
            ReplyToCommand(client, "Bought %s for %d gold, %d left.", g_StoreInventory[item], GetItemCost(client,item), PlayerGoldCount[client]);
        }
    }
    else if (action == MenuAction_End) // If the menu has ended, destroy it
    {
        CloseHandle(menu);
    }
} // ShopMenuHandler()

public Action:Command_SayShop(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    if (args == 0) // No args, display shop menu
    {
        new Handle:hShopMenu = CreateMenu(ShopMenuHandler);
        SetMenuTitle(hShopMenu, "Ye Olde Shoppe [%i gold]", PlayerGoldCount[client]);
        for (new i=0; i<MAX_POTIONS; i++)
        {
            decl String:MenuItemDisplay[64];
            decl String:MenuItemInfo[64];
            Format(MenuItemDisplay, sizeof(MenuItemDisplay), "%16s (%d gold, %d on hand)", g_StoreInventory[i], GetItemCost(client, i), PlayerPotions[client][i]);
            Format(MenuItemInfo, sizeof(MenuItemInfo), "%i", i);
            AddMenuItem(hShopMenu, MenuItemInfo, MenuItemDisplay);
        }
        SetMenuExitButton(hShopMenu, true);
        DisplayMenu(hShopMenu, client, 20);
    } // menu
    else if (args == 1) // shop by direct number
    {
        decl String:text[192];
        GetCmdArgString(text, sizeof(text));
        new bought = GetItemFromText(text);

        if (bought > -1)
        {
            if (!CanBuyItem(client,bought))
            {
                ReplyToCommand(client, "You can not afford %s.", g_StoreInventory[bought]);
                bought = -1;
            }
        }
        else
        {
            ReplyToCommand(client, "Unknown item.");
        }

        if (bought != -1)
        {
            BuyItem(client,bought);
            ReplyToCommand(client, "Bought %s. You have %d gold left.", g_StoreInventory[bought], PlayerGoldCount[client]);
        }
    } // direct buy

    return Plugin_Handled;
} // Command_SayShop()


// -----------------------------------------------------------------------------
// Command Drink
//
public DrinkMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
    if (action == MenuAction_Select) // If an option was selected, buy the potion (if possible)
    {
        new String:info[32];
        GetMenuItem(menu, param2, info, sizeof(info));

        new client = param1;
        new item = StringToInt(info);

        // Param1 = client
        // Param2 = menu #, does not always correspond to the list index due to pages
        // info = string of the menu info, which we set as the list index # (and convert to integer)

        // Check to see if the person is already rtd'ing
        if(PlayerEffectTracker[client][PLAYER_STATUS])
        {
            ReplyToCommand(client, "Just used a potion. Please wait a few seconds.");
            return;
        }

        if (PlayerPotions[client][item] < 1)
        {
            item = -1;
        }

        if (item == -1)
        {
            ReplyToCommand(client, "You don't have this item.");
        }
        else
        {
            PlayerPotions[client][item ] = PlayerPotions[client][item ] - 1;
            ApplyItemEffect(client, item);
            ReplyToCommand(client, "Using %s...",g_StoreInventory[item]);
        }
    }
    else if (action == MenuAction_End) // If the menu has ended, destroy it
    {
        CloseHandle(menu);
    }
} // DrinkMenuHandler()

public Action:Command_SayDrink(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    if (args == 0)
    {
        new Handle:hDrinkMenu = CreateMenu(DrinkMenuHandler);
        SetMenuTitle(hDrinkMenu, "Drink a potion:");

        for (new i=0; i<MAX_POTIONS; i++)
        {
            decl String:MenuItemDisplay[64];
            decl String:MenuItemInfo[64];
            Format(MenuItemDisplay, sizeof(MenuItemDisplay), "%s x %d", g_StoreInventory[i], PlayerPotions[client][i]);
            Format(MenuItemInfo, sizeof(MenuItemInfo), "%i", i);
            AddMenuItem(hDrinkMenu, MenuItemInfo, MenuItemDisplay);
        }
        SetMenuExitButton(hDrinkMenu, true);
        DisplayMenu(hDrinkMenu, client, 20);
    }
    else
    {
        decl String:text[192];
        GetCmdArgString(text, sizeof(text));
        new item = GetItemFromText(text);

        if (item != -1)
        {
            if (PlayerPotions[client][item] < 1)
            {
                item = -1;
            }
        }

        if (item == -1)
        {
            ReplyToCommand(client, "You don't have this item.");
        }
        else
        {
            if (PlayerEffectTracker[client][PLAYER_STATUS])
            {
                ReplyToCommand(client, "Just used a potion. Please wait a few seconds.");
                return Plugin_Handled;
            }

            PlayerPotions[client][item] = PlayerPotions[client][item] - 1;
            ApplyItemEffect(client, item);
            ReplyToCommand(client, "Using %s...",g_StoreInventory[item]);
        }
    }

    return Plugin_Handled;
} // Command_SayDrink()


// -----------------------------------------------------------------------------
// Command QuickDrink
//
public QuickDrinkMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
    if (action == MenuAction_Select) // If an option was selected, buy the potion (if possible)
    {
        new String:info[32];
        GetMenuItem(menu, param2, info, sizeof(info));

        new client = param1;
        new item = StringToInt(info);

        // Param1 = client
        // Param2 = menu #, does not always correspond to the list index due to pages
        // info = string of the menu info, which we set as the list index # (and convert to integer)
        if  (!CanBuyItem(client, item))
        {
            ReplyToCommand(client, "You can not afford %s.", g_StoreInventory[item]);
        }
        else
        {
            BuyItem(client, item);

            // Check to see if the person is already under the effects of a potion
            if (PlayerEffectTracker[client][PLAYER_STATUS])
            {
                ReplyToCommand(client, "Just used a potion, but still bought %s for %d. You have %d gold left.", g_StoreInventory[item], GetItemCost(client,item), PlayerGoldCount[client]);
                return;
            }

            PlayerPotions[client][item] = PlayerPotions[client][item] - 1;
            ApplyItemEffect(client, item);
            ReplyToCommand(client, "Bought and drank %s for %d. You have %d gold left.", g_StoreInventory[item], GetItemCost(client,item), PlayerGoldCount[client]);
        }
    }
    else if (action == MenuAction_End) // If the menu has ended, destroy it
    {
        CloseHandle(menu);
    }
} // QuickDrinkMenuHandler()

public Action:Command_SayqDrink(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    if (args == 0) // No args, display shop menu
    {
        new Handle:hQDrinkMenu = CreateMenu(QuickDrinkMenuHandler);
        SetMenuTitle(hQDrinkMenu, "Ye Olde Shoppe: (You have %i gold)", PlayerGoldCount[client]);
        for (new i=0; i<MAX_POTIONS; i++)
        {
            decl String:MenuItemDisplay[64];
            decl String:MenuItemInfo[64];
            Format(MenuItemDisplay, sizeof(MenuItemDisplay), "%16s (%d gold, %d on hand)", g_StoreInventory[i], GetItemCost(client, i), PlayerPotions[client][i]);
            Format(MenuItemInfo, sizeof(MenuItemInfo), "%i", i);
            AddMenuItem(hQDrinkMenu, MenuItemInfo, MenuItemDisplay);
        }
        SetMenuExitButton(hQDrinkMenu, true);
        DisplayMenu(hQDrinkMenu, client, 20);
    } // menu
    else if (args == 1) // shop by direct number
    {
        decl String:text[192];
        GetCmdArgString(text, sizeof(text));
        new bought = StringToInt(text);

        if (bought > -1)
        {
            if (!CanBuyItem(client,bought))
            {
                ReplyToCommand(client, "You can not afford %s.", g_StoreInventory[bought]);
                bought = -1;
            }
        }
        else
        {
            ReplyToCommand(client, "Unknown item.");
        }

        if (bought != -1)
        {
            BuyItem(client, bought);
            PlayerPotions[client][bought] = PlayerPotions[client][bought] - 1;
            ApplyItemEffect(client, bought);
            ReplyToCommand(client, "Bought and drank %s for %d. You have %d gold left.", g_StoreInventory[bought], GetItemCost(client, bought), PlayerGoldCount[client]);
        }
    } // direct buy

    return Plugin_Handled;
} // Command_SayqDrink()


public Action:Command_SayAutoshop(client, args)
{
    new PluginEnabled = GetConVarInt(g_hCvarEnable);
    if (PluginEnabled == 0)
    {
        return Plugin_Handled;
    }

    if (args == 0)
    {
        ReplyToCommand(client, "usage: /autoshop # or /autoshop -1. Current Setting: %d",PlayerAutoBuy[client]);
        return Plugin_Handled;
    }

    decl String:text[192];
    GetCmdArgString(text, sizeof(text));

    new item = StringToInt(text);

    if ((item>0 && item> MAX_POTIONS) || (item<0 && item<MAX_POTIONS*-1))
    {
         item = 0;
    }

    PlayerAutoBuy[client] = item;

    if (item>0)
    {
         ReplyToCommand(client, "AutoShop will try to buy: %s.", g_StoreInventory[PlayerAutoBuy[client]-1]);
         CheckAutoBuy(client);
    }
    else if (item < 0)
    {
         ReplyToCommand(client, "AutoShop will try to buy up to: %s.", g_StoreInventory[(PlayerAutoBuy[client]*-1)-1]);
         CheckAutoBuy(client);
    }
    else
    {
         ReplyToCommand(client, "AutoShop disabled.");
    }


    return Plugin_Handled;
}




public CheckAutoBuy(client)
{

    new PluginEnabled = GetConVarInt(g_hCvarEnable);
    if (PluginEnabled == 0)
    {
        return;
    }

    if (!IsFakeClient(client) && IsClientInGame(client))
    {
        new item  = PlayerAutoBuy[client] ;

        //Buy Up To Logic
        if (item < 0 )
        {
            new  start = (PlayerAutoBuy[client]*-1) -1;
            for (new j = 0; (j<=start && PlayerGoldCount[client]>GetItemCost(client,0)) ;j++)
            {
                if (PlayerPotions[client][j] ==0 && CanBuyItem(client,j))
                {
                    BuyItem(client,j);
                    PrintToChat(client, "AutoShop: Bought %s for %dg. Gold Remaining: %d.",g_StoreInventory[j],GetItemCost(client,j), PlayerGoldCount[client]);
                }
            }
        }
        // Buy only one item
        else if (item >0)
        {
            while (CanBuyItem(client,item-1))
            {
                BuyItem(client,item-1);
                PrintToChat(client, "AutoShop: Bought %s for %dg. Gold Remaining: %d.",g_StoreInventory[item-1],GetItemCost(client,item-1), PlayerGoldCount[client]);
            }
        }
    }
}


public Action:Command_SayBotTest(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    for (new i=1; i<MaxClients; i++)
    {
        if (!IsClientInGame(i)) continue;

        decl String:PlayerName[64];
        new String:SteamID[64];
        GetClientName(i, PlayerName, sizeof(PlayerName));
        GetClientAuthString(i, SteamID, sizeof(SteamID));

        new ammo = 0;
        new primary = 1;
        new secondary = 2;
        //new metal = 3;

        if (StrEqual(SteamID, "BOT"))
        {
            PrintToServer("[MF] Removing ammo on %s(%i)", PlayerName, i);
            IsPlayerAWitch[i] = 0;
            PlayerBounty[i] = 0;
            SetEntData(i, FindDataMapOffs(i, "m_iAmmo") + (_:primary * 4), ammo, 4);
            SetEntData(i, FindDataMapOffs(i, "m_iAmmo") + (_:secondary * 4), ammo, 4);
        }
    } // loop players

    return Plugin_Handled;
} // Command_SayBotTest()


public Action:Command_SayRepent(client, args)
{
    if (!g_CvarEnable) return Plugin_Handled;

    if (IsPlayerAWitch[client] == 0)
    {
        PrintToChat(client, "Thou hast not sinned, thus you can not repent.");
        return Plugin_Handled;
    }

    new gold = PlayerBounty[client]+5;

    if (gold>10)
    {
        gold =10;
    }

    if (PlayerGoldCount[client] < gold)
    {
        PrintToChat(client, "Failure - repenting for your sins requires %i gold.",gold);
        return Plugin_Handled;
    }
    else
    {
        RemoveGold(client,gold);
        OnPlayerRepent(client);
    }

    return Plugin_Handled;
} // Command_SayRepent()



// EOF
